home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
src
/
haeberli
/
libgutil
/
hideline.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
30KB
|
1,578 lines
/*
* Copyright 1991, 1992, 1993, 1994, Silicon Graphics, Inc.
* All Rights Reserved.
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
* the contents of this file may not be disclosed to third parties, copied or
* duplicated in any form, in whole or in part, without the prior written
* permission of Silicon Graphics, Inc.
*
* RESTRICTED RIGHTS LEGEND:
* Use, duplication or disclosure by the Government is subject to restrictions
* as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
* and Computer Software clause at DFARS 252.227-7013, and/or in similar or
* successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
* rights reserved under the Copyright Laws of the United States.
*/
/*
* hideline -
* A hidden line algotithm.
*
* Paul Haeberli - 1990
*
* exports
*
void hiddendirdrop(dir,thresh)
void hiddencolorthresh(delta) in range 0.0..1.0
void hiddensilwidth(min,max)
void hiddenhalowidth(wid)
void hiddenfacewidths(min,max,inter)
void hiddenextend(sil,face,var)
void hiddenline(tlname,dfunc,wfunc)
void beginhideline(dfunc,wfunc);
void hiddentri(atile)
void endhideline();
*
*/
#include "stdio.h"
#include "math.h"
#include "trilist.h"
#include "simple.h"
#include "vect.h"
#include "hideline.h"
float frand();
void beginhideline();
void endhideline();
void hiddentri();
#define ISTRANS(c) (((c)>>24) == 0x00)
typedef struct edge { /* first 4 lines must be identical to tile struct */
struct edge *next;
FLOAT xmin, xmax;
FLOAT ymin, ymax;
FLOAT zmin, zmax;
VECT edgeeq;
VECT pos[2];
long col[2];
int backfacing;
int type;
FLOAT delc;
} edge;
static edge *edgemalloc();
static void freeedge();
static edge *cloneedge();
static void freeedgelist();
static tile *tilemalloc();
static void freetile();
static void freetilelist();
static FLOAT edgedist2d();
static FLOAT planedist3d();
static FLOAT cdist();
static FLOAT colordel();
static int geomsame();
static int geommatch0();
static int geommatch1();
static int colorsame();
static int colormatch0();
static int colormatch1();
static int vertsame();
static int hasarea();
static void edgedomain();
static FLOAT silwidth();
static void extendedge();
static tile *freepast();
static void findedges();
static int bbox2d();
static int bbox3d();
static int vsame();
static int edgeontri();
static int edgeintertri();
static int posinside();
static int tritriinter();
static int couldhide();
static int edgeinbackoftriplane();
static int trisplitedge();
static void planesplitedge();
static void hidehaloedge();
static int haloedge();
static void dohidehaloedge();
static void dohideedge();
static void dohidepoint();
static int compar();
static tile *ysortlist();
static void putline();
static void readtilelist(char *name);
#define NOBACKFACE
#define NINCHUNK 300
#define WIDTH_MIN (0.0001)
#define EDGEEXTEND_SIL (0.1)
#define EDGEEXTEND_INT (0.0)
#define EDGEEXTEND_MIN (0.0) /* these are scaled by EDGEEXTEND_SIL */
#define EDGEEXTEND_MAX (1.0)
#define ALMOSTPLANAR (0.999)
#define EDGETYPE_UNKNOWN 0
#define EDGETYPE_SIL 1
#define EDGETYPE_INT 2
#define EDGETYPE_LINE 3
#define EDGETYPE_POINT 4
#define EDGETYPE_TEXT 5
#define INTER_NONE 0
#define INTER_TOUCHES 1
#define INTER_COVERS 2
static int (*linefunc)();
static int (*widthfunc)();
static edge *halohead;
static FLOAT curwidth;
static FLOAT cthresh = 0.1;
static FLOAT silwidthmin = 0.002;
static FLOAT silwidthmax = 0.006;
static FLOAT halowidth = 0.008;
static FLOAT faceminwidth = 0.0005;
static FLOAT facemaxwidth = 0.0015;
static FLOAT intersectwidth = 0.0005;
static FLOAT extendsil = 0.05;
static FLOAT extendface = 0.05;
static FLOAT extendvar = 0.5;
static FLOAT putwidth = -1.0;
static edge *fedges;
static tile *ftiles;
static VECT dropdir;
static FLOAT dropthresh = 0.0;
static void putpoint(float *p, float width);
/*
* config functions
*
*
*/
void hiddendirdrop(dir,thresh)
vect *dir;
float thresh;
{
dropdir.x = dir->x;
dropdir.y = dir->y;
dropdir.z = dir->z;
VNORMAL(&dropdir);
dropthresh = thresh;
}
void hiddencolorthresh(delta) /* 0.0..1.0 */
float delta;
{
cthresh = delta;
}
void hiddensilwidth(min,max)
float min, max;
{
silwidthmin = min;
silwidthmax = max;
}
void hiddenhalowidth(wid)
float wid;
{
halowidth = wid;
}
void hiddenfacewidths(min,max,inter)
float min, max, inter;
{
faceminwidth = min;
facemaxwidth = min;
intersectwidth = inter;
}
void hiddenextend(sil,face,var)
float sil,face,var;
{
extendsil = sil;
extendface = face;
extendvar = var;
}
/*
* fast alloc for edges and tiles
*
*
*/
static edge *edgemalloc()
{
edge *e;
int i;
if(!fedges) {
e = (edge *)mymalloc(NINCHUNK*sizeof(edge));
for(i=0; i<NINCHUNK; i++)
freeedge(e++);
}
e = fedges;
fedges = fedges->next;
return e;
}
static void freeedge(e)
edge *e;
{
if( e ) {
e->next = fedges;
fedges = e;
}
}
static edge *cloneedge(e)
edge *e;
{
edge *c;
c = edgemalloc();
*c = *e;
c->next = 0;
return c;
}
static void freeedgelist(e)
edge *e;
{
edge *ne;
if(e) {
while(e) {
ne = e->next;
freeedge(e);
e = ne;
}
}
}
static tile *tilemalloc()
{
tile *t;
int i;
if(!ftiles) {
t = (tile *)mymalloc(NINCHUNK*sizeof(tile));
for(i=0; i<NINCHUNK; i++)
freetile(t++);
}
t = ftiles;
ftiles = ftiles->next;
return t;
}
static void freetile(t)
tile *t;
{
if( t ) {
t->next = ftiles;
ftiles = t;
}
}
static void freetilelist(t)
tile *t;
{
tile *nt;
if(t) {
while(t) {
nt = t->next;
freetile(t);
t = nt;
}
}
}
/*
* hidden line stuff follows
*
*
*/
void hiddenline(tlname,dfunc,wfunc)
char *tlname;
int (*dfunc)();
int (*wfunc)();
{
beginhideline(dfunc,wfunc);
readtilelist(tlname);
endhideline();
}
static tile *tiles;
static edge *edgelist;
void beginhideline(dfunc,wfunc)
int (*dfunc)();
int (*wfunc)();
{
linefunc = dfunc;
widthfunc = wfunc;
tiles = 0;
edgelist = 0;
}
void endhideline()
{
tiles = ysortlist(tiles);
findedges(tiles,edgelist);
}
static FLOAT edgedist2d(edgeeq,pos)
VECT *edgeeq, *pos;
{
return (edgeeq->x*pos->x) + (edgeeq->y*pos->y) + edgeeq->w;
}
static FLOAT planedist3d(planeeq,pos)
VECT *planeeq, *pos;
{
return (planeeq->x*pos->x) +
(planeeq->y*pos->y) +
(planeeq->z*pos->z) + planeeq->w;
}
static edge *lineedge(tile *t, int v1, int v2, int type)
{
edge *e;
e = edgemalloc();
e->pos[0] = t->pos[v1];
e->col[0] = t->col[v1];
e->pos[1] = t->pos[v2];
e->col[1] = t->col[v2];
e->backfacing = 0;
e->type = type;
edgedomain(e);
return e;
}
static void readtilelist(char *name)
{
tile atile;
int i, ntri;
trilisttri tri;
ntri = tlopen(name);
for(i=0; i<ntri; i++) {
tlread(&tri);
atile.pos[0].x = ASPECT*tri.x0;
atile.pos[0].y = tri.y0;
atile.pos[0].z = tri.z0;
atile.pos[1].x = ASPECT*tri.x1;
atile.pos[1].y = tri.y1;
atile.pos[1].z = tri.z1;
atile.pos[2].x = ASPECT*tri.x2;
atile.pos[2].y = tri.y2;
atile.pos[2].z = tri.z2;
atile.col[0] = tri.c0;
atile.col[1] = tri.c1;
atile.col[2] = tri.c2;
hiddentri(&atile);
}
tlclose();
}
void hiddentri(atile)
tile *atile;
{
VECT norm, temp;
FLOAT dx, dy, w, mag;
int j, s0, s1, s2;
tile *ttile;
edge *e;
ttile = tilemalloc();
*ttile = *atile;
atile = ttile;
atile->transparent = 0;
atile->transparent |= ISTRANS(atile->col[0]);
atile->transparent |= ISTRANS(atile->col[1]);
atile->transparent |= ISTRANS(atile->col[2]);
atile->col[0] &= 0xffffff;
atile->col[1] &= 0xffffff;
atile->col[2] &= 0xffffff;
if(TRINORMAL(atile->pos+0,atile->pos+1,atile->pos+2,&norm,TOLERANCE/100.0)) {
if(norm.z<0.0) {
#ifdef NOBACKFACE
freetile(atile);
return;
#else
norm.x = -norm.x;
norm.y = -norm.y;
norm.z = -norm.z;
temp = atile->pos[1];
atile->pos[1] = atile->pos[2];;
atile->pos[2] = temp;
atile->backfacing = 1;
#endif
} else {
atile->backfacing = 0;
}
VPLANE(&norm,atile->pos+0,&atile->plane);
for(j=0; j<3; j++) {
dx = atile->pos[(j+1)%3].y-atile->pos[j].y;
dy = atile->pos[(j+1)%3].x-atile->pos[j].x;
mag = sqrt(dx*dx+dy*dy);
dx = dx/mag;
dy = -dy/mag;
w = dx*atile->pos[j].x+dy*atile->pos[j].y;
atile->edgeeq[j].x = dx;
atile->edgeeq[j].y = dy;
atile->edgeeq[j].w = -w;
}
atile->xmin = atile->xmax = atile->pos[0].x;
atile->ymin = atile->ymax = atile->pos[0].y;
atile->zmin = atile->zmax = atile->pos[0].z;
for(j=1; j<3; j++) {
if(atile->xmin>atile->pos[j].x)
atile->xmin=atile->pos[j].x;
if(atile->xmax<atile->pos[j].x)
atile->xmax=atile->pos[j].x;
if(atile->ymin>atile->pos[j].y)
atile->ymin=atile->pos[j].y;
if(atile->ymax<atile->pos[j].y)
atile->ymax=atile->pos[j].y;
if(atile->zmin>atile->pos[j].z)
atile->zmin=atile->pos[j].z;
if(atile->zmax<atile->pos[j].z)
atile->zmax=atile->pos[j].z;
}
atile->next = tiles;
tiles = atile;
} else {
s0 = vertsame(atile->pos+0,atile->pos+1);
s1 = vertsame(atile->pos+1,atile->pos+2);
s2 = vertsame(atile->pos+2,atile->pos+0);
if(s0 && s1 && s2) {
e = lineedge(atile,0,0,EDGETYPE_POINT);
e->next = edgelist;
edgelist = e;
} else if(s0 || s1 || s2) {
if(s0)
e = lineedge(atile,1,2,EDGETYPE_LINE);
else
e = lineedge(atile,0,1,EDGETYPE_LINE);
e->next = edgelist;
edgelist = e;
} else {
fprintf(stderr,"very small tri found!!\n");
}
freetile(atile);
}
}
static FLOAT cdist(c0,c1)
long c0, c1;
{
int d, td;
d = ((c0>>0)&0xff) - ((c1>>0)&0xff);
if(d<0)
d = -d;
td = d;
d = ((c0>>8)&0xff) - ((c1>>8)&0xff);
if(d<0)
d = -d;
td += d;
d = ((c0>>16)&0xff) - ((c1>>16)&0xff);
if(d<0)
d = -d;
td += d;
return td/(3*255.0);
}
static FLOAT colordel(e0,e1,ord)
edge *e0, *e1;
int ord;
{
switch(ord) {
case 1:
return (cdist(e0->col[0],e1->col[0]) + cdist(e0->col[1],e1->col[1]))/2.0;
break;
case 2:
return (cdist(e0->col[0],e1->col[1]) + cdist(e0->col[1],e1->col[0]))/2.0;
break;
default:
fprintf(stderr,"colordel: bad poop\n");
exit(1);
break;
}
}
static int geomsame(e0,e1)
edge *e0, *e1;
{
if(geommatch1(e0,e1))
return 2;
return 0;
}
#define POSDIFF(a,b) ((a)!=(b))
static int geommatch0(e0,e1)
edge *e0, *e1;
{
VECT *v0, *v1;
v0 = e0->pos+0;
v1 = e1->pos+0;
if(POSDIFF(v0->x,v1->x))
return 0;
if(POSDIFF(v0->y,v1->y))
return 0;
if(POSDIFF(v0->y,v1->y))
return 0;
v0 = e0->pos+1;
v1 = e1->pos+1;
if(POSDIFF(v0->x,v1->x))
return 0;
if(POSDIFF(v0->y,v1->y))
return 0;
if(POSDIFF(v0->y,v1->y))
return 0;
return 1;
}
static int geommatch1(e0,e1)
edge *e0, *e1;
{
VECT *v0, *v1;
v0 = e0->pos+0;
v1 = e1->pos+1;
if(POSDIFF(v0->x,v1->x))
return 0;
if(POSDIFF(v0->y,v1->y))
return 0;
if(POSDIFF(v0->y,v1->y))
return 0;
v0 = e0->pos+1;
v1 = e1->pos+0;
if(POSDIFF(v0->x,v1->x))
return 0;
if(POSDIFF(v0->y,v1->y))
return 0;
if(POSDIFF(v0->y,v1->y))
return 0;
return 1;
}
static int colorsame(e0,e1)
edge *e0, *e1;
{
if(colormatch0(e0,e1))
return 1;
if(colormatch1(e0,e1))
return 2;
return 0;
}
static int colormatch0(e0,e1)
edge *e0, *e1;
{
if(cdist(e0->col[0],e1->col[0])>=cthresh)
return 0;
if(cdist(e0->col[1],e1->col[1])>=cthresh)
return 0;
return 1;
}
static int colormatch1(e0,e1)
edge *e0, *e1;
{
if(cdist(e0->col[0],e1->col[1])>=cthresh)
return 0;
if(cdist(e0->col[1],e1->col[0])>=cthresh)
return 0;
return 1;
}
static int vertsame(v0,v1)
FLOAT *v0, *v1;
{
if(v0[0] != v1[0])
return 0;
if(v0[1] != v1[1])
return 0;
if(v0[2] != v1[2])
return 0;
return 1;
}
static int hasarea(tri)
trilisttri *tri;
{
if(vertsame(&tri->x0,&tri->x1))
return 0;
if(vertsame(&tri->x1,&tri->x2))
return 0;
if(vertsame(&tri->x2,&tri->x0))
return 0;
return 1;
}
static void edgedomain(e)
edge *e;
{
FLOAT dx, dy, mag, w;
e->xmin = e->xmax = e->pos[0].x;
e->ymin = e->ymax = e->pos[0].y;
e->zmin = e->zmax = e->pos[0].z;
if(e->xmin>e->pos[1].x)
e->xmin=e->pos[1].x;
if(e->xmax<e->pos[1].x)
e->xmax=e->pos[1].x;
if(e->ymin>e->pos[1].y)
e->ymin=e->pos[1].y;
if(e->ymax<e->pos[1].y)
e->ymax=e->pos[1].y;
if(e->zmin>e->pos[1].z)
e->zmin=e->pos[1].z;
if(e->zmax<e->pos[1].z)
e->zmax=e->pos[1].z;
dx = e->pos[1].y-e->pos[0].y;
dy = e->pos[1].x-e->pos[0].x;
mag = sqrt(dx*dx+dy*dy);
dx = dx/mag;
dy = -dy/mag;
w = dx*e->pos[0].x+dy*e->pos[0].y;
e->edgeeq.x = dx;
e->edgeeq.y = dy;
e->edgeeq.w = -w;
}
static FLOAT silwidth(e)
edge *e;
{
FLOAT dx, dy, mag, val;
dx = e->pos[1].x - e->pos[0].x;
dy = e->pos[1].y - e->pos[0].y;
mag = sqrt(dx*dx+dy*dy);
val = (1.0+(dx/mag))/2.0;
return FLERP(silwidthmin,silwidthmax,val);
}
static void extendedge(e,ee,exmag)
edge *e, *ee;
float exmag;
{
FLOAT dx, dy, dz, mag, extend;
dx = e->pos[1].x-e->pos[0].x;
dy = e->pos[1].y-e->pos[0].y;
dz = e->pos[1].z-e->pos[0].z;
mag = sqrt(dx*dx+dy*dy);
if(mag>TOLERANCE) {
extend = exmag*FLERP(1.0-extendvar,1.0+extendvar,frand());
if(extend<0.0)
extend = 0.0;
dx = (extend*dx)/mag;
dy = (extend*dy)/mag;
dz = (extend*dz)/mag;
ee->pos[0].x = e->pos[0].x-dx;
ee->pos[0].y = e->pos[0].y-dy;
ee->pos[0].z = e->pos[0].z-dz+0.0001;
ee->pos[1].x = e->pos[1].x+dx;
ee->pos[1].y = e->pos[1].y+dy;
ee->pos[1].z = e->pos[1].z+dz+0.0001;
edgedomain(ee);
ee->backfacing = e->backfacing;
} else
*ee = *e;
}
static tile *freepast(tlist,y)
tile *tlist;
FLOAT y;
{
tile *tl, *ntl;
while(tlist && tlist->ymax<y) {
ntl = tlist->next;
freetile(tlist);
tlist = ntl;
}
if(tlist) {
tl = tlist;
while(tl->next) {
if(tl->next->ymin>y)
return tlist;
if(tl->next->ymax<y) {
ntl = tl->next->next;
freetile(tl->next);
tl->next = ntl;
} else
tl = tl->next;
}
}
return tlist;
}
static int dodropedge(edge *e)
{
VECT dir;
FLOAT dx, dy, dz, dot;
if(dropthresh < 0.0001)
return 0;
VSUB(e->pos+0,e->pos+1,&dir);
VNORMAL(&dir);
dot = VDOT(&dir,&dropdir);
if(dot<0.0)
dot = -dot;
if(dot<dropthresh)
return 0;
else
return 1;
}
static void findedges(tile *tlist, edge *edgelist)
{
int i, gs;
edge *e, *cur, *curp, *head;
edge eedge;
tile *tl, *otl;
FLOAT top, maxextend;
edge interedge;
edge *halotail;
maxextend = (1.0+extendvar)*MAX(EDGEEXTEND_SIL,EDGEEXTEND_INT);
/* get edges from all the triangles */
tl = tlist;
while(tl) {
e = edgemalloc();
e->pos[0] = tl->pos[0];
e->col[0] = tl->col[0];
e->pos[1] = tl->pos[1];
e->col[1] = tl->col[1];
e->backfacing = tl->backfacing;
e->type = EDGETYPE_UNKNOWN;
edgedomain(e);
e->next = edgelist;
edgelist = e;
e = edgemalloc();
e->pos[0] = tl->pos[1];
e->col[0] = tl->col[1];
e->pos[1] = tl->pos[2];
e->col[1] = tl->col[2];
e->backfacing = tl->backfacing;
e->type = EDGETYPE_UNKNOWN;
edgedomain(e);
e->next = edgelist;
edgelist = e;
e = edgemalloc();
e->pos[0] = tl->pos[2];
e->col[0] = tl->col[2];
e->pos[1] = tl->pos[0];
e->col[1] = tl->col[0];
e->backfacing = tl->backfacing;
e->type = EDGETYPE_UNKNOWN;
edgedomain(e);
e->next = edgelist;
edgelist = e;
tl = tl->next;
}
/* sort the edges in y */
edgelist = (edge *)ysortlist(edgelist);
/* Classify all edges */
head = edgelist;
halohead = 0;
halotail = 0;
while(head) {
curp = head;
cur = head->next;
top = head->ymax;
if(head && head->type == EDGETYPE_UNKNOWN) {
/* find another edge with the same geometry */
while(cur) {
if(cur->ymin>top) {
cur = 0;
break;
}
if(gs=geomsame(cur,head) && cur->type == EDGETYPE_UNKNOWN)
break;
curp = cur;
cur = cur->next;
}
/* if geometry is unique, the edge is a silouette edge */
if(!cur) {
head->type = EDGETYPE_SIL;
/* clone it and add it to the halo list */
cur = cloneedge(head);
if(!halohead) {
halohead = cur;
halotail = cur;
} else {
halotail->next = cur;
halotail = cur;
}
/* if geometry is duplicated it's an internal edge */
} else {
if(!colorsame(cur,head)) {
head->delc = colordel(cur,head,gs);
head->type = EDGETYPE_INT;
}
e = curp->next;
curp->next = cur->next;
freeedge(e);
}
}
head = head->next;
}
/* find all the places where two triangles intersect */
tl = tlist;
curwidth = intersectwidth;
while(tl) {
otl = tl->next;
while(otl) {
if(otl->ymin>tl->ymax)
break;
if(tritriinter(tl,otl,&interedge))
hidehaloedge(tlist,halohead,&interedge);
otl = otl->next;
}
tl = tl->next;
}
/* go thru the edges in order */
head = edgelist;
while(head) {
/* free triangles past */
tlist = freepast(tlist,head->ymin-maxextend);
if(dodropedge(head)) {
/* if drop edge */
} else if(head->type == EDGETYPE_SIL || head->type == EDGETYPE_LINE) {
/* if silouette edge */
#ifdef DASHEDLINES
curwidth = WIDTH_MIN;
extendedge(head,&eedge,extendsil);
hidehaloedge(tlist,halohead,&eedge);
curwidth = silwidth(head);
dashedge(head);
hidehaloedge(tlist,halohead,head);
#endif
curwidth = silwidth(head);
extendedge(head,&eedge,extendsil);
hidehaloedge(tlist,halohead,&eedge);
} else if(head->type == EDGETYPE_INT) {
/* if internal edge */
curwidth = FLERP(faceminwidth,facemaxwidth,head->delc);
extendedge(head,&eedge,extendface);
hidehaloedge(tlist,halohead,&eedge);
} else if(head->type == EDGETYPE_POINT) {
/* if point */
dohidepoint(tlist,&eedge);
}
head = head->next;
}
freeedgelist(edgelist);
freeedgelist(halohead);
freetilelist(tlist);
}
static int bbox2d(e,t)
edge *e;
tile *t;
{
if(e->xmax<=t->xmin)
return 0;
if(t->xmax<=e->xmin)
return 0;
if(e->ymax<=t->ymin)
return 0;
if(t->ymax<=e->ymin)
return 0;
return 1;
}
static int bbox3d(e,t)
edge *e;
tile *t;
{
if(e->xmax<=t->xmin)
return 0;
if(t->xmax<=e->xmin)
return 0;
if(e->ymax<=t->ymin)
return 0;
if(t->ymax<=e->ymin)
return 0;
if(e->zmax<=t->zmin)
return 0;
if(t->zmax<=e->zmin)
return 0;
return 1;
}
static int vsame(v1,v2)
VECT *v1, *v2;
{
if(v1->x != v2->x)
return 0;
if(v1->y != v2->y)
return 0;
if(v1->z != v2->z)
return 0;
return 1;
}
static int edgeontri(e,t)
edge *e;
tile *t;
{
int i, j;
for(i=0; i<3; i++) {
if(vsame(e->pos+0,t->pos+i)) {
for(j=0; j<3; j++) {
if(vsame(e->pos+1,t->pos+j)) {
fprintf(stderr,"NEVER\n");
return 1;
}
}
return 0;
}
}
return 0;
}
static int edgeintertri(e,t)
edge *e;
tile *t;
{
int i, in;
FLOAT dmin, dmax;
FLOAT d, d0, d1;
/* see if the triangle is entirely on one side of the edge */
dmin = dmax = edgedist2d(&e->edgeeq,t->pos+0);
for(i=1; i<3; i++) {
d = edgedist2d(&e->edgeeq,t->pos+i);
if(dmin>d)
dmin = d;
if(dmax<d)
dmax = d;
}
if(dmin>-TOLERANCE || dmax<TOLERANCE)
return INTER_NONE;
/* see if the edge is outside all triangle edges */
in = 0;
for(i=0; i<3; i++) {
d0 = dmin = dmax = edgedist2d(t->edgeeq+i,e->pos+0);
d1 = edgedist2d(t->edgeeq+i,e->pos+1);
if(dmin>d1)
dmin = d1;
if(dmax<d1)
dmax = d1;
if(dmin>-TOLERANCE)
return INTER_NONE;
if(dmax<TOLERANCE)
in++;
}
if(in == 3)
return INTER_COVERS;
else
return INTER_TOUCHES;
}
static int posinside(p,t)
VECT *p;
tile *t;
{
int i;
FLOAT d;
for(i=0; i<3; i++) {
d = edgedist2d(t->edgeeq+i,p);
if(d>-TOLERANCE)
return 0;
}
return 1;
}
static int tritriinter(t1,t2,e)
tile *t1, *t2;
edge *e;
{
FLOAT d[3];
int i, l, g, il, ig, al, ag;
int lpos[3], gpos[3];
int ngood, ngot;
FLOAT goodparam[6], dot;
VECT *goodpos1[6], *goodpos2[6];
tile *goodtri[6];
VECT pos;
if(!bbox3d(t1,t2))
return 0;
dot = VDOT(&t1->plane,&t2->plane);
if(dot<0.0)
dot = -dot;
if(dot>ALMOSTPLANAR)
return 0;
ngood = 0;
l = g = 0;
for(i=0; i<3; i++) {
d[i] = planedist3d(&t1->plane,&t2->pos[i]);
if(d[i]<-TOLERANCE)
lpos[l++] = i;
else if(d[i]>TOLERANCE)
gpos[g++] = i;
}
if((l==0) || (g==0))
return 0;
for(il=0; il<l; il++) {
for(ig=0; ig<g; ig++) {
al = lpos[il];
ag = gpos[ig];
goodparam[ngood] = d[al]/(d[al]-d[ag]);
goodpos1[ngood] = &t2->pos[al];
goodpos2[ngood] = &t2->pos[ag];
goodtri[ngood] = t1;
ngood++;
}
}
l = g = 0;
for(i=0; i<3; i++) {
d[i] = planedist3d(&t2->plane,&t1->pos[i]);
if(d[i]<-TOLERANCE)
lpos[l++] = i;
else if(d[i]>TOLERANCE)
gpos[g++] = i;
}
if((l==0) || (g==0))
return 0;
for(il=0; il<l; il++) {
for(ig=0; ig<g; ig++) {
al = lpos[il];
ag = gpos[ig];
goodparam[ngood] = d[al]/(d[al]-d[ag]);
goodpos1[ngood] = &t1->pos[al];
goodpos2[ngood] = &t1->pos[ag];
goodtri[ngood] = t2;
ngood++;
}
}
ngot = 0;
for(g=0; g<ngood; g++) {
VLERP(goodpos1[g],goodpos2[g],&pos,goodparam[g]);
if(posinside(&pos,goodtri[g])) {
e->pos[ngot] = pos;
ngot++;
if(ngot == 2) {
edgedomain(e);
return 1;
}
}
}
return 0;
}
static int couldhide(e,t)
edge *e;
tile *t;
{
if(t->zmax<=e->zmin)
return 0;
else
return 1;
}
static int edgeinbackoftriplane(e,t,d0,d1)
edge *e;
tile *t;
FLOAT *d0, *d1;
{
*d0 = planedist3d(&t->plane,e->pos+0);
*d1 = planedist3d(&t->plane,e->pos+1);
if( ((*d0)<-TOLERANCE) || ((*d1)<-TOLERANCE) )
return 1;
else
return 0;
}
static int trisplitedge(e,t,e1,e2)
edge *e;
tile *t;
edge *e1, *e2;
{
int i;
FLOAT d0, d1, dmin, dmax;
FLOAT param;
for(i=0; i<3; i++) {
d0 = dmin = dmax = edgedist2d(t->edgeeq+i,e->pos+0);
d1 = edgedist2d(t->edgeeq+i,e->pos+1);
if(dmin>d1)
dmin = d1;
if(dmax<d1)
dmax = d1;
if(dmax>TOLERANCE && dmin<-TOLERANCE) {
param = -d0/(d1-d0);
d0 = dmin = dmax = edgedist2d(&e->edgeeq,t->pos+i);
d1 = edgedist2d(&e->edgeeq,t->pos+((i+1)%3));
if(dmin>d1)
dmin = d1;
if(dmax<d1)
dmax = d1;
if(dmax>-TOLERANCE && dmin<TOLERANCE) {
e1->pos[0] = e->pos[0];
VLERP(e->pos+0,e->pos+1,e1->pos+1,param);
edgedomain(e1);
e1->edgeeq = e->edgeeq;
VLERP(e->pos+0,e->pos+1,e2->pos+0,param);
e2->pos[1] = e->pos[1];
edgedomain(e2);
e2->edgeeq = e->edgeeq;
return 1;
}
}
}
return 0;
}
static void planesplitedge(e,p,e1,e2)
edge *e;
VECT *p;
edge *e1, *e2;
{
e1->pos[0] = e->pos[0];
e1->pos[1] = *p;
edgedomain(e1);
e1->edgeeq = e->edgeeq;
e2->pos[0] = *p;
e2->pos[1] = e->pos[1];
edgedomain(e2);
e2->edgeeq = e->edgeeq;
}
static void hidehaloedge(tlist,halo,e)
tile *tlist;
edge *halo;
edge *e;
{
handdown();
dohidehaloedge(tlist,halo,e,0);
}
static int haloedge(e,halo,e1,e2)
edge *e, *halo;
edge *e1, *e2;
{
FLOAT d0, d1, del;
FLOAT param, ze, zh;
FLOAT p1, p2;
int ret;
/* classify halo end points wrt edge */
d0 = edgedist2d(&e->edgeeq,halo->pos+0);
d1 = edgedist2d(&e->edgeeq,halo->pos+1);
if(d1>d0) {
if(d1<TOLERANCE || d0>-TOLERANCE)
return -1;
} else {
if(d0<TOLERANCE || d1>-TOLERANCE)
return -1;
}
param = -d0/(d1-d0);
zh = FLERP(halo->pos[0].z,halo->pos[1].z,param);
/* classify edge end points wrt halo */
d0 = edgedist2d(&halo->edgeeq,e->pos+0);
d1 = edgedist2d(&halo->edgeeq,e->pos+1);
if(d1>d0) {
if(d1<TOLERANCE || d0>-TOLERANCE)
return -1;
del = d1-d0;
} else {
if(d0<TOLERANCE || d1>-TOLERANCE)
return -1;
del = d0-d1;
}
param = -d0/(d1-d0);
ze = FLERP(e->pos[0].z,e->pos[1].z,param);
/* compare the depths, if halo in back of edge, return */
if(zh<(ze+TOLERANCE))
return -1;
/* find parameter value for split edge */
p1 = param-(halowidth/del);
p2 = param+(halowidth/del);
ret = 0;
if(p1>0.0) {
e1->pos[0] = e->pos[0];
VLERP(e->pos+0,e->pos+1,e1->pos+1,p1);
edgedomain(e1);
e1->edgeeq = e->edgeeq;
ret |= 1;
}
if(p2<1.0) {
e2->pos[1] = e->pos[1];
VLERP(e->pos+0,e->pos+1,e2->pos+0,p2);
edgedomain(e2);
e2->edgeeq = e->edgeeq;
ret |= 2;
}
return ret;
}
static void dohidehaloedge(tlist,halo,e,level)
tile *tlist;
edge *halo;
edge *e;
int level;
{
int stat, n;
FLOAT top;
edge e1, e2;
top = e->ymax;
while(halo) {
if(halo->ymin>top)
break;
if( bbox2d(e,halo) && couldhide(e,halo)) {
n=haloedge(e,halo,&e1,&e2);
switch(n) {
case 0:
return;
case 1:
dohidehaloedge(tlist,halo,&e1,level+1);
return;
case 2:
dohidehaloedge(tlist,halo,&e2,level+1);
return;
case 3:
dohidehaloedge(tlist,halo,&e1,level+1);
dohidehaloedge(tlist,halo,&e2,level+1);
return;
}
}
halo = halo->next;
}
/* if not halo'ed at all, put out the line */
dohideedge(tlist,e,0);
}
static void dohideedge(tlist,e,level)
tile *tlist;
edge *e;
int level;
{
int stat;
edge e1, e2;
FLOAT top, d0, d1, param;
VECT planepos;
top = e->ymax;
while(tlist) {
if(tlist->ymin>top)
break;
if( (tlist->transparent==0) && bbox2d(e,tlist) &&
couldhide(e,tlist) && edgeinbackoftriplane(e,tlist,&d0,&d1)) {
/* edge crosses plane of triangle */
if((d0*d1)<-TOLERANCE) {
param = d0/(d0-d1);
VLERP(e->pos+0,e->pos+1,&planepos,param);
if(posinside(&planepos,tlist)) { /* edge goes thru */
planesplitedge(e,&planepos,&e1,&e2);
dohideedge(tlist,&e1,level+1);
dohideedge(tlist,&e2,level+1);
return;
}
}
/* 2d triangle intersect */
stat = edgeintertri(e,tlist);
if(stat == INTER_TOUCHES) {
if(trisplitedge(e,tlist,&e1,&e2)) {
dohideedge(tlist,&e1,level+1);
dohideedge(tlist,&e2,level+1);
return;
} else {
fprintf(stderr,"split failed\n");
exit(1);
}
}
if(stat == INTER_COVERS)
return;
}
tlist = tlist->next;
}
/* if not obscured at all, put out the line */
putline(e->pos+0,e->pos+1,curwidth);
}
static void dohidepoint(tlist,e)
tile *tlist;
edge *e;
{
int stat;
edge e1, e2;
FLOAT top, d0, d1, param;
VECT planepos;
top = e->ymax;
while(tlist) {
if(tlist->ymin>top)
break;
if( bbox2d(e,tlist) && couldhide(e,tlist)) {
if(!posinside(&e->pos[0],tlist)) { /* XXXX what */
return;
}
}
tlist = tlist->next;
}
/* if not obscured at all, put out the line */
putpoint((float *)e->pos+0,curwidth);
}
static void putpoint(float *p, float width)
{
if(width!=putwidth) {
putwidth = width;
widthfunc(putwidth);
}
linefunc(p,p);
}
static int compar(p0,p1)
tile **p0, **p1;
{
FLOAT y0, y1;
y0 = (*p0)->ymin;
y1 = (*p1)->ymin;
if(y0<y1)
return 1;
if(y0==y1)
return 0;
else
return -1;
}
static tile *ysortlist(tiles)
tile *tiles;
{
tile *t, **all, **tpp;
int i, n;
n = 0;
t = tiles;
while(t) {
t = t->next;
n++;
}
all = (tile **)mymalloc(n*sizeof(tile*));
t = tiles;
tpp = all;
while(t) {
*tpp++ = t;
t = t->next;
}
qsort(all,n,sizeof(tile *),compar);
t = 0;
tpp = all;
while(n--) {
(*tpp)->next = t;
t = *tpp++;
}
free(all);
return t;
}
static void putline(p0,p1,width)
VECT *p0, *p1;
FLOAT width;
{
float v0[3], v1[3];
v0[0] = p0->x;
v0[1] = p0->y;
v0[2] = 0.0;
v1[0] = p1->x;
v1[1] = p1->y;
v1[2] = 0.0;
if(width!=putwidth) {
putwidth = width;
widthfunc(putwidth);
}
handline(linefunc,v0,v1);
}
#ifdef DASHEDLINES
dashedge(e)
edge *e;
{
setlinestyle(1);
bgnline();
V2F(&e->pos[0]);
V2F(&e->pos[1]);
endline();
setlinestyle(0);
}
#endif
/*
*
* graphical debugging stuff
*
*/
#ifdef NOTDEF
#define POSDEL 0.01
drawtilelist(tlist)
tile *tlist;
{
reshapeviewport();
ortho(-1.1*ASPECT,1.1*ASPECT,-1.1,1.1,-2.0,2.0);
rgb(1.0,1.0,1.0);
clear();
while(tlist) {
cpack(0x000000ff);
drawtile(tlist);
tlist = tlist->next;
}
}
drawpos(p)
VECT *p;
{
move2(p->x-POSDEL,p->y);
draw2(p->x+POSDEL,p->y);
move2(p->x,p->y-POSDEL);
draw2(p->x,p->y+POSDEL);
}
tridraw(tri)
trilisttri *tri;
{
cpack(0x000000ff);
bgnclosedline();
V2F(&tri->x0);
V2F(&tri->x1);
V2F(&tri->x2);
endclosedline();
}
drawinter(e,t)
edge *e;
tile *t;
{
FLOAT xmin, xmax;
FLOAT ymin, ymax;
FLOAT xavg, yavg;
xmin = MIN(e->xmin,t->xmin);
xmax = MAX(e->xmax,t->xmax);
ymin = MIN(e->ymin,t->ymin);
ymax = MAX(e->ymax,t->ymax);
xavg = (xmin+xmax)/2.0;
yavg = (ymin+ymax)/2.0;
pushmatrix();
scale(10.0,10.0,1.0);
translate(-xavg,-yavg,0.0);
translate(-0.05,-0.05,0.0);
drawedge(e);
drawtile(t);
popmatrix();
}
drawedge(e)
edge *e;
{
bgnline();
V2F(e->pos+0);
V2F(e->pos+1);
endline();
}
drawtile(t)
tile *t;
{
bgnclosedline();
V2F(t->pos+0);
V2F(t->pos+1);
V2F(t->pos+2);
endclosedline();
}
printtile(t)
tile *t;
{
int i;
for(i=0; i<3; i++) {
fprintf(stderr,"t%d: %f %f %f\n",
i,t->pos[i].x,t->pos[i].y,t->pos[i].z);
}
fprintf(stderr,"\n");
}
printedge(e)
edge *e;
{
fprintf(stderr,"p0: %f %f %f c0: 0x%08x\n",
e->pos[0].x,e->pos[0].y,e->pos[0].z,e->col[0]);
fprintf(stderr,"p1: %f %f %f c1: 0x%08x\n",
e->pos[1].x,e->pos[1].y,e->pos[1].z,e->col[1]);
fprintf(stderr,"\n");
}
#endif